package com.demo.unittest.springweb.controller;

import com.demo.unittest.springweb.bean.JSONResponse;
import com.demo.unittest.springweb.bean.User;
import com.demo.unittest.springweb.service.UserService;
import com.demo.unittest.springweb.util.DateUtil;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
import static org.powermock.api.mockito.PowerMockito.mockStatic;

/**
 * 使用powermock增强. 演示mock静态方法
 * 下面的代码loginController里, DataUtil的静态方法和LoggerFactory都是mock的.
 *
 * 想mock代码里直接new对象的情况, 也需要powermock:
 * Second second = Mockito.mock(Second.class);
 * whenNew(Second.class).withNoArguments().thenReturn(second);
 *
 * @author tzp
 * @since 2018/5/14
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest({LoginController.class, DateUtil.class, LoggerFactory.class})
public class LoginControllerTestPlus {

    @Mock
    private UserService mockUserService;
    @Mock
    private Logger mockLogger;

    //在这写new和@InjectMocks, 下面的mockStatic还没生效. 这不写inject, setup的时候要手动设置进去.
    private LoginController loginController;

    @Before
    public void setup() throws IllegalAccessException {
        User user = new User();
        user.setId(1L);
        user.setName("rightName");
        user.setPassword("rightPass");

        when(mockUserService.authenticateUser(anyString(), anyString()))
                .thenReturn(null);
        when(mockUserService.authenticateUser("rightName", "rightPass"))
                .thenReturn(user);

        mockStatic(DateUtil.class);
        when(DateUtil.dateToStr(any(Date.class))).thenReturn("2018-05-01");

        mockStatic(LoggerFactory.class);
        when(LoggerFactory.getLogger(any(Class.class))).thenReturn(mockLogger);

        loginController = new LoginController();
        FieldUtils.writeField(loginController, "userService", mockUserService, true);
    }

    @Test
    public void login() throws Exception {
        //arrange
        HttpServletRequest request = mock(HttpServletRequest.class);
        //act
        JSONResponse json = loginController.login(request, "rightName", "rightPass");
        JSONResponse json1 = loginController.login(request, "rightName", "xxx");
        //assert
        assertEquals(0, json.getCode());
        assertEquals(1, json1.getCode());
        assertEquals("2018-05-01", json1.getData());
    }

}